package com.uum.admin.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.uum.admin.dto.UserAuthDTO;
import com.uum.admin.pojo.entity.SysRole;
import com.uum.admin.pojo.entity.SysUser;
import com.uum.admin.pojo.entity.SysUserRole;
import com.uum.admin.pojo.query.UserPageQuery;
import com.uum.admin.pojo.vo.UserPageVO;
import com.uum.admin.mapper.SysUserMapper;
import com.uum.admin.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.uum.blog.api.BlogFeignClient;
import com.uum.common.core.constant.GlobalConstants;
import com.uum.common.core.enums.UserCreateMethod;
import com.uum.mq.api.MqFeignClient;
import com.uum.web.exception.BizException;
import com.uum.web.util.JwtUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private final SysUserRoleService sysUserRoleService;
    private final SysRoleService sysRoleService;
    private final SysPermissionService sysPermissionService;
    private final PasswordEncoder passwordEncoder;
    private final RedisTemplate redisTemplate;
    private final MqFeignClient mqFeignClient;
    private final BlogFeignClient blogFeignClient;

    @Override
    public UserAuthDTO getUserByUsername(String username) {
        return baseMapper.getUserByUsername(username);
    }

    @Override
    public SysUser getUserInfoByUserId(Long userId) {
        return baseMapper.getUserInfoByUserId(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(SysUser user) {
        valid(user);
        List<Long> beforeRoleIds = sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, user.getId()).select(SysUserRole::getRoleId))
                .stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        SysUser sysUser = baseMapper.selectById(user.getId());
        String beforeNickname = sysUser.getNickname();
        //修改用户
        baseMapper.updateUser(user);
        //判断有无修改昵称
        if (!user.getNickname().equals(beforeNickname)) {
            blogFeignClient.updateAuthorName(user.getId(),user.getNickname());
        }
        //判读有无修改角色
        List<Long> afterRoleIds = user.getRoleIds();
        if (!(beforeRoleIds.size() == afterRoleIds.size() && beforeRoleIds.containsAll(afterRoleIds))) {
            //修改用户-角色
            sysUserRoleService.saveOrUpdate(user.getId(), user.getRoleIds());
            sysPermissionService.refreshPermRolesRules();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUser(SysUser user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setCreateMethod(UserCreateMethod.SYSTEM.name());
        user.setStatus(GlobalConstants.STATUS_YES);
        user.setCreateUserId(JwtUtils.getUserId());
        //添加用户
        int insert = baseMapper.insert(user);
        if (insert > 0) {
            //TODO 线程异步优化
            //添加用户-角色
            sysUserRoleService.saveOrUpdate(user.getId(), user.getRoleIds());
            //添加已读消息
            mqFeignClient.saveReadMsgByUser(user.getId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeDeleteBatch(List<String> ids) {
        //删除用户-角色相关的用户
        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().in("user_id", ids));
        //删除用户已读消息
        mqFeignClient.delMsgByUserId(ids);
        //删除用户
        baseMapper.completeDeleteBatch(ids);
    }

    @Override
    public IPage<UserPageVO> pageUser(UserPageQuery userPageQuery) {
        Page<UserPageVO> page = new Page(userPageQuery.getCurrentPage(), userPageQuery.getPageSize());
        //非管理人员只查询他创建的用户和他自己
        QueryWrapper<UserPageVO> queryWrapper = new QueryWrapper<>();
        if (!JwtUtils.isAdministrator()) {
            Long userId = JwtUtils.getUserId();
            queryWrapper.eq("t1.create_user_id", userId);
            queryWrapper.or().eq("t1.id", userId);
            userPageQuery.setCreateUserId(JwtUtils.getUserId());
        }
        //获取状态
        Integer status = userPageQuery.getStatus();
        //获取角色
        String role = userPageQuery.getRole();
        //判断角色是否为空
        boolean roleFlag = StrUtil.isNotBlank(role);
        queryWrapper.like(StrUtil.isNotBlank(userPageQuery.getNickname()), "t1.nickname", userPageQuery.getNickname())
                .eq(status != null && status == 0, "t1.status", 1)
                .eq(status != null && status == 0, "t1.is_disabled", 0)
                .eq(status != null && status == 1, "t1.is_disabled", 1)
                .eq(status != null && status == 2, "t1.status", 0)
                .in(roleFlag, "t3.role_id", roleFlag ? Arrays.asList(role.split(",")) : null)
                .groupBy("t1.id");
        List<UserPageVO> userList = baseMapper.pageUser(page, queryWrapper);
        page.setRecords(userList);
        return page;
    }

    @Override
    @Transactional
    public boolean register(SysUser user) {
        //1.保存用户
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        //默认超级管理员为创建者
        user.setCreateUserId(1l);
        user.setCreateMethod(UserCreateMethod.REGISTER.name());
        int count = baseMapper.insert(user);
        if (count > 0) {
            //TODO 线程异步优化
            //赋予普通用户的角色
            if (saveUserRole(user.getId(),GlobalConstants.USER_ROLE_CODE)) {
                //发送激活邮件
                sendMail(user);
            }
            //添加已读消息
            mqFeignClient.saveReadMsgByUser(user.getId());
        }
        return count > 0;
    }

    @Override
    public boolean saveUserRole(Long userId, String roleCode) {
        //查询角色的ID
        SysRole sysRole = sysRoleService.getOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getCode,roleCode).select(SysRole::getRoleId));
        //设置用户的角色为指定角色
        SysUserRole role = new SysUserRole();
        role.setUserId(userId);
        role.setRoleId(sysRole.getRoleId());
        //保存角色
        return sysUserRoleService.save(role);
    }

    @Override
    @Transactional
    public boolean activeUser(String token) {
        // 从redis中获取用户信息
        String key = "ACTIVATE_USER:" + token;
        String userInfo = (String) redisTemplate.opsForValue().get(key);
        if (StrUtil.isEmpty(userInfo)) {
            throw new BizException("激活码已失效或过期...请重新获取");
        }
        SysUser sysUser = JSON.parseObject(userInfo, SysUser.class);
        SysUser update = new SysUser();
        update.setId(sysUser.getId());
        update.setStatus(1);
        int result = baseMapper.updateById(update);
        if (result > 0) {
            redisTemplate.delete(key);
            //不推送该账号创建前已有的消息
            mqFeignClient.readAll(sysUser.getId());
        }
        return result > 0;
    }

    @Override
    public boolean afreshActive(String username) {
        SysUser user = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
        if (user != null) {
            sendMail(user);
            return true;
        }
        return false;
    }

    @Override
    public boolean disabledUser(Long id, Integer status) {
        SysUser user = new SysUser();
        user.setId(id);
        user.setIsDisabled(status);
        valid(user);
        return baseMapper.updateById(user) > 0;
    }

    public void sendMail(SysUser user) {
        //1.生成随机激活的token
        String token = IdUtil.simpleUUID();
        //2.过滤密码
        user.setPassword("");
        //3.将从数据库查询的数据缓存到redis中，用于用户邮箱激活，1小时后过期
        redisTemplate.opsForValue().set("ACTIVATE_USER:" + token, JSON.toJSONString(user),1, TimeUnit.HOURS);
        //4.发送邮件，进行账号激活
        mqFeignClient.sendActivateEmail(user.getNickname(), user.getUsername(), token);
    }


    /**
     * 判断有无越权
     * @param user
     */
    private void valid(SysUser user) {
        if (JwtUtils.isAdministrator()) {
            return;
        }
        Long updateUserId = user.getId();
        Long createUserId = baseMapper.selectById(updateUserId).getCreateUserId();
        if (JwtUtils.getUserId() != createUserId) {
            throw new BizException("无权修改该账号");
        }
    }
}
